package com.alisls.shequtao.service.goods.aspect;

import com.alisls.shequtao.common.service.entity.BizDO;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * DAO类保存和更新切面，在保存或更新之前自动给createTime或updateTime字段赋值
 *
 * @author Ke Wang
 * @since 2020/11/6
 */
@Component
@Aspect
public class DaoSaveAndUpdateMethodAspect {

    /**
     * DTO类创建时间字段名称
     */
    private static final String CREATE_TIME_FIELD = "createTime";

    /**
     * DTO类修改时间字段名称
     */
    private static final String UPDATE_TIME_FIELD = "updateTime";

    /**
     * 保存方法以save开头的方法切面
     * TODO 切面包名写死了
     */
    @Pointcut("execution(* com.alisls.shequtao.service.*.dao..*.save*(..))")
    public void saveMethod() {
    }

    /**
     * 保存方法以add开头的方法切面
     */
    @Pointcut("execution(* com.alisls.shequtao.service.*.dao..*.add*(..))")
    public void addMethod() {
    }

    /**
     * 保存方法以insert开头的方法切面
     */
    @Pointcut("execution(* com.alisls.shequtao.service.*.dao..*.insert*(..))")
    public void insertMethod() {
    }

    /**
     * 更新方法以update开头的方法切面
     */
    @Pointcut("execution(* com.alisls.shequtao.service.*.dao..*.update*(..))")
    public void updateMethod() {
    }

    /**
     * 更新方法以modify开头的方法切面
     */
    @Pointcut("execution(* com.alisls.shequtao.service.*.dao..*.modify*(..))")
    public void modifyMethod() {
    }

    /**
     * 更新方法以edit开头的方法切面
     */
    @Pointcut("execution(* com.alisls.shequtao.service.*.dao..*.edit*(..))")
    public void editMethod() {
    }

    /**
     * 在所有保存方法执行前进行拦截(保存方法的方法名必须式以save或add或insert开头)
     * 取出所有方法的参数，将参数对象为BizDO类的属性createTime赋值
     * @param joinPoint
     */
    @Before("saveMethod()||addMethod()||insertMethod()")
    public void beforeSave(JoinPoint joinPoint) {
        // 获取方法的所有参数
        Object[] args = joinPoint.getArgs();
        if (args == null || args.length <= 0) {
            return;
        }

        for (Object arg: args) {
            // 判断参数是否BizDTO类，如果不是则忽略
            if (!(arg instanceof BizDO)) {
                continue;
            }
            BizDO bizDTO = (BizDO) arg;
            Date createTime = getCreateOrUpdateTime(bizDTO, CREATE_TIME_FIELD);
            if (createTime == null) {
                createTime = new Date();
                bizDTO.setCreateTime(createTime);
            }
        }
    }

    /**
     * 在所有更新方法执行前进行拦截(更新方法的方法名必须式以update或modify或edit开头)
     * 取出所有方法的参数，将参数对象为BizDO类的属性createTime赋值
     * @param joinPoint
     */
    @Before("saveMethod()||addMethod()||insertMethod()")
    public void beforeUpdate(JoinPoint joinPoint) {
        // 获取方法的所有参数
        Object[] args = joinPoint.getArgs();
        if (args == null || args.length <= 0) {
            return;
        }

        for (Object arg: args) {
            // 判断参数是否BizDTO类，如果不是则忽略
            if (!(arg instanceof BizDO)) {
                continue;
            }
            BizDO bizDTO = (BizDO) arg;
            bizDTO.setUpdateTime(new Date());
        }
    }

    /**
     * 获取BizDTO对象字段createTime或updateTime字段的值
     * @param fieldName
     * @return Date
     */
    private Date getCreateOrUpdateTime(BizDO bizDO, String fieldName) {
        // 方法名
        fieldName = "get" +
                fieldName.substring(0, 1).toUpperCase() +
                fieldName.substring(1);
        try {
            Method method = BizDO.class.getMethod(fieldName);
            Date date = (Date) method.invoke(bizDO);
            return date;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

}
